<template>
  <div ref="canvas"></div>
</template>

<script lang="ts" setup>
import * as THREE from "three";
import Stats from "three/examples/jsm/libs/stats.module";
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { ref, onMounted } from "vue";
import {addLargeGroundPlane, initDefaultLighting} from "@/book/ThreeUtils";

const canvas = ref();
// 场景
const scene = new THREE.Scene();
// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x000000);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.shadowMap.enabled = true;
// 相机
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight);
camera.position.set(50, 50, 50);
camera.lookAt(0,0,0);
// 相机控件
const orbitControl = new OrbitControls(camera, renderer.domElement);
orbitControl.update();
// 性能统计
const stat = Stats();
// 光照
initDefaultLighting(scene, undefined);
// 地面
addLargeGroundPlane(scene, true);
// gui
const controls = {
  cubePosX: 0,
  cubePosY: 3,
  cubePosZ: 10,

  spherePosX: 10,
  spherePosY: 5,
  spherePosZ: 0,

  groupPosX: 10,
  groupPosY: 5,
  groupPosZ: 0,

  grouping: false,
  rotate: false,

  cubeScale: 1,
  sphereScale: 1,
  groupScale: 1,

  redraw: () => {
    if (scene.getObjectByName("group")) {
      scene.remove(scene.getObjectByName("group"));
    }

    const sphereGeom = new THREE.SphereGeometry(5, 10, 10);
    const sphereMaterial = new THREE.MeshNormalMaterial();
    const sphere = new THREE.Mesh(sphereGeom, sphereMaterial);
    sphere.name = "sphere";
    sphere.position.set(controls.spherePosX, controls.spherePosY, controls.spherePosZ);
    sphere.scale.set(controls.sphereScale, controls.sphereScale, controls.sphereScale);

    const cubeGeom = new THREE.BoxGeometry(6, 6, 6);
    const cubeMaterial = new THREE.MeshNormalMaterial();
    const cube = new THREE.Mesh(cubeGeom, cubeMaterial);
    cube.name = "cube";
    cube.position.set(controls.cubePosX, controls.cubePosY, controls.cubePosZ);
    cube.scale.set(controls.cubeScale, controls.cubeScale, controls.cubeScale);

    const group = new THREE.Group();
    group.name = "group";
    group.position.set(controls.groupPosX, controls.groupPosY, controls.groupPosZ);
    group.scale.set(controls.groupScale, controls.groupScale, controls.groupScale);
    group.add(sphere);
    group.add(cube);

    scene.add(group);

    if (scene.getObjectByName("arrow")) {
      scene.remove(scene.getObjectByName("arrow"));
    }
    const arrow = new THREE.ArrowHelper(new THREE.Vector3(0, 1, 0), group.position, 10, 0x0000ff);
    arrow.name = "arrow";
    scene.add(arrow);
  },
};
const gui = new GUI();
// @ts-ignore
gui.add(controls, "grouping");
// @ts-ignore
gui.add(controls, "rotate");

const sphereFolder = gui.addFolder("sphere");
// @ts-ignore
sphereFolder.add(controls, "spherePosX", -20, 20).onChange((e) => {
  scene.getObjectByName("sphere").position.x = e;
  controls.redraw();
});
// @ts-ignore
sphereFolder.add(controls, "spherePosZ", -20, 20).onChange((e) => {
  scene.getObjectByName("sphere").position.z = e;
  controls.redraw();
});
// @ts-ignore
sphereFolder.add(controls, "spherePosY", -20, 20).onChange((e) => {
  scene.getObjectByName("sphere").position.y = e;
  controls.redraw();
});
// @ts-ignore
sphereFolder.add(controls, "sphereScale", 0, 3).onChange((e) => {
  scene.getObjectByName("sphere").scale.set(e, e, e);
  controls.redraw();
});

const cubeFolder = gui.addFolder("cube");
// @ts-ignore
cubeFolder.add(controls, "cubePosX", -20, 20).onChange((e) => {
  scene.getObjectByName("cube").position.x = e;
  controls.redraw();
});
// @ts-ignore
cubeFolder.add(controls, "cubePosZ", -20, 20).onChange((e) => {
  scene.getObjectByName("cube").position.z = e;
  controls.redraw();
});
// @ts-ignore
cubeFolder.add(controls, "cubePosY", -20, 20).onChange((e) => {
  scene.getObjectByName("cube").position.y = e;
  controls.redraw();
});
// @ts-ignore
cubeFolder.add(controls, "cubeScale", 0, 3).onChange((e) => {
  scene.getObjectByName("cube").scale.set(e, e, e);
  controls.redraw();
});

const groupFolder = gui.addFolder("group");
// @ts-ignore
groupFolder.add(controls, "groupPosX", -20, 20).onChange((e) => {
  scene.getObjectByName("group").position.x = e;
  controls.redraw();
});
// @ts-ignore
groupFolder.add(controls, "groupPosZ", -20, 20).onChange((e) => {
  scene.getObjectByName("group").position.z = e;
  controls.redraw();
});
// @ts-ignore
groupFolder.add(controls, "groupPosY", -20, 20).onChange((e) => {
  scene.getObjectByName("group").position.y = e;
  controls.redraw();
});
// @ts-ignore
groupFolder.add(controls, "groupScale", 0, 3).onChange((e) => {
  scene.getObjectByName("group").scale.set(e, e, e);
  controls.redraw();
});

controls.redraw();

let step = 0.02;
const render = () => {
  stat.update();

  if (controls.rotate) {
    scene.getObjectByName("sphere").rotation.y += step;
    scene.getObjectByName("cube").rotation.y += step;
  }

  if (controls.grouping && controls.rotate) {
    scene.getObjectByName("group").rotation.y += step;
  }

  requestAnimationFrame(render);
  renderer.render(scene, camera);
};
onMounted(() => {
  canvas.value.appendChild(stat.domElement);
  canvas.value.appendChild(renderer.domElement);
  render();
});
</script>
